Medium 清新閱讀版
:連結
今天讓我們看看幾個重要的 PHPUnit @
Annotation 吧!
所謂的 PHPUnit @
Annotation,是指在測試案例函數前的 PHP Doc 區塊,PHPUnit 提供開發者引用的 @
Annotation。PHPUnit 提供的 @
Annotation 大約有 20+ 個,今天會和大家介紹最常用的幾個。
首先,大家請先閱讀以下程式碼,後續的@
Annotation 範例皆是以此為測試目標:
app/Services/TestService.php
<?php
namespace App\Services;
use Exception;
class TestService
{
/**
* @throws Exception
*/
public function calculateBmi(float $height, float $weight): float
{
if ($weight <= 0 || $height <= 0) {
throw new Exception('Invalid input!', 1);
}
return $weight / ($height * $height);
}
}
@test
介紹:當測試程式碼中的函數之 PHP Doc 區塊有引用此 Annotation 時,PHPUnit方會將此函數當成測試案例函數執行。
說到這邊,可能有些讀者會覺得奇怪,過去兩週的文章中,有很多範例測試函數都沒有使用
@test
,為什麼仍可以正常執行?
原因是,除了測試程式碼中的有引用@test
的函數 PHPUnit 會當成測試案例函數來執行,若一個測試程式碼中的函數,是以test
為開頭,如testCanCalcuateBmi()
,那麼 PHPUnit 也會把它當測試案例函數來執行。
範例:
<?php
namespace Tests\Feature;
use App\Services\TestService;
use Exception;
use Tests\TestCase;
class ExceptionTest extends TestCase
{
/**
* @test
*/
public function canCalcuateBmi()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$bmiActual = $service->calculateBmi(64.0, 1.6);
$bmiExpected = 64.0/(1.6^2);
$this->assertEquals($bmiExpected, $bmiActual);
}
public function testCanCalcuateBmi()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$bmiActual = $service->calculateBmi(64.0, 1.6);
$bmiExpected = 64.0/(1.6^2);
$this->assertEquals($bmiExpected, $bmiActual);
}
public function canCalcuateBmi2()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$bmiActual = $service->calculateBmi(64.0, 1.6);
$bmiExpected = 64.0/(1.6^2);
$this->assertEquals($bmiExpected, $bmiActual);
}
}
以上程式碼中,canCalcuateBmi()
、 testCanCalcuateBmi()
兩函數都會被執行,canCalcuateBmi2()
則不會。
@depends
介紹:當測試程式碼中的函數之 PHP Doc 區塊有引用此 Annotation ,則 PHPUnit 會確認其依賴的測試案例函數有驗證通過,方會執行當前的測試案例涵數。
範例:
<?php
namespace Tests\Feature;
use App\Services\TestService;
use Exception;
use Tests\TestCase;
class ExceptionTest extends TestCase
{
public function testCanCalcuateBmi()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$bmiActual = $service->calculateBmi(64.0, 1.6);
$bmiExpected = 64.0/(1.6^2);
$this->assertEquals($bmiExpected, $bmiActual);
}
/**
* @depends testCanCalcuateBmi
*/
public function testCanThrowExceptionWhenInvaliHeight()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$service->calculateBmi(0.0, 1.0);
}
}
以上程式碼中,當 testCanCalcuateBmi()
驗證通過時,testCanThrowExceptionWhenInvaliHeight()
才會被執行;當testCanCalcuateBmi()
測試失敗時,testCanThrowExceptionWhenInvaliHeight()
不會被執行。
@group
介紹:顧名思義,此 Annotation 可以將多個測試案例函數分組。
範例:
<?php
namespace Tests\Feature;
use App\Services\TestService;
use Exception;
use Tests\TestCase;
class ExceptionTest extends TestCase
{
/**
* @group BMI
*/
public function testCanCalcuateBmi()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$bmiActual = $service->calculateBmi(64.0, 1.6);
$bmiExpected = 64.0/(1.6^2);
$this->assertEquals($bmiExpected, $bmiActual);
}
/**
* @group BMI
*/
public function testCanThrowExceptionWhenInvaliHeight()
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$service->calculateBmi(0.0, 1.0);
}
}
以上程式碼中,當我們在命令列執行 ./vendor/bin/phpunit --group=BMI
時, testCanCalcuateBmi()
及 testCanThrowExceptionWhenInvaliHeight()
都會被執行。除此之外,一個測試案例函數可以被歸類在多個 @group
喔!
@testWith
介紹:此 Annotation 可以讓我們對同一個測試案例函數,執行一組以上資料組的測試驗證。
範例:
<?php
namespace Tests\Feature;
use App\Services\TestService;
use Exception;
use Tests\TestCase;
class ExceptionTest extends TestCase
{
/**
* @testWith [0.0, 1.0]
* [1.0, 0.0]
* [0.0, 0.0]
*/
public function testCanThrowExceptionWhenInvalidData(float $height, float $weight)
{
$service = app(TestService::class);
$this->expectException(Exception::class);
$service->calculateBmi($height, $weight);
}
}
以上程式碼中, testCanThrowExceptionWhenInvalidData()
會被執行3次:
testCanThrowExceptionWhenInvalidData(0.0, 1.0)
testCanThrowExceptionWhenInvalidData(1.0, 0.0)
testCanThrowExceptionWhenInvalidData(0.0, 0.0)
@dataProvider
@testWith
類似,但使用方式比較特別,姑且讓我們保留到下一篇文章再做介紹。 ?以上就是今天的介紹,大家可以多演練一下唷!
明天來為大家介紹 setUp()、tearDown()、Data Provider 這三個特殊函數!